using System.Collections.Generic;
using UnityEngine;

public class FlightSequence : BallFlight
{
	public delegate void OnCollisionDelegate(Vector3 hitPoint, Vector3 hitVel, HitObjectTag hitObject);

	public class FlightPlanStage
	{
		public FlightParams startParams;

		public BallFlight flight;

		public HitObjectTag hitObjectTag;

		public float duration;

		public float startTime;

		public bool useUnityPhysics;

		public void Clear()
		{
			if (flight != null)
			{
				flight.ReturnToPool();
			}
			flight = null;
		}
	}

	public struct NetHitInfo
	{
		public Vector3 optionalNetHitNormal;

		public Vector3 position;
	}

	public OnCollisionDelegate onCollision;

	private List<FlightPlanStage> stages = new List<FlightPlanStage>();

	private int stageCount;

	private int activeStageIndex;

	public NetHitInfo netHitInfo;

	public float timeToLand { get; set; }

	public Vector3 landingPos { get; set; }

	public float flightDuration { get; protected set; }

	public bool isActive
	{
		get
		{
			return base.flightTime < flightDuration;
		}
	}

	public FlightPlanStage GetFirstStage()
	{
		if (stages.Count > 0)
		{
			return stages[0];
		}
		return null;
	}

	public FlightPlanStage LastStage()
	{
		if (stages.Count > 0 && stageCount > 0)
		{
			return stages[stageCount - 1];
		}
		return null;
	}

	public FlightPlanStage GetStageThatStartsFromTableSide(float tableSide)
	{
		for (int i = 0; i < stageCount; i++)
		{
			FlightPlanStage flightPlanStage = stages[i];
			if (Mathf.Sign(flightPlanStage.startParams.position.z) == Mathf.Sign(tableSide))
			{
				return flightPlanStage;
			}
		}
		return null;
	}

	public float GetTimeToStage(FlightPlanStage endStage)
	{
		float num = 0f;
		for (int i = 0; i < stageCount; i++)
		{
			FlightPlanStage flightPlanStage = stages[i];
			if (flightPlanStage == endStage)
			{
				break;
			}
			num += flightPlanStage.duration;
		}
		return num;
	}

	private FlightPlanStage AddStage(BallFlight flight)
	{
		stageCount++;
		if (stageCount >= stages.Count)
		{
			stages.Add(new FlightPlanStage());
		}
		FlightPlanStage flightPlanStage = stages[stageCount - 1];
		flightPlanStage.flight = flight;
		flightPlanStage.duration = 0f;
		flightPlanStage.useUnityPhysics = false;
		return flightPlanStage;
	}

	public void ClearStages()
	{
		stageCount = 0;
		activeStageIndex = 0;
		flightDuration = 0f;
		foreach (FlightPlanStage stage in stages)
		{
			stage.Clear();
		}
	}

	private FlightPlanStage GetActiveStage()
	{
		if (stageCount <= 0)
		{
			return null;
		}
		return stages[Mathf.Clamp(activeStageIndex, 0, stageCount - 1)];
	}

	private int GetStageIndexForTime(float time)
	{
		float num = 0f;
		for (int i = 0; i < stageCount; i++)
		{
			num += stages[i].duration;
			if (time < num)
			{
				return i;
			}
		}
		return stageCount - 1;
	}

	public FlightPlanStage AddStage(BallFlight flight, FlightParams startParams, float duration, bool useUnityPhysics, HitObjectTag hitObjectTag)
	{
		stageCount++;
		if (stageCount >= stages.Count)
		{
			stages.Add(new FlightPlanStage());
		}
		FlightPlanStage flightPlanStage = stages[stageCount - 1];
		float startTime = 0f;
		if (stageCount >= 2)
		{
			FlightPlanStage flightPlanStage2 = stages[stageCount - 2];
			startTime = flightPlanStage2.startTime + flightPlanStage2.duration;
		}
		flightPlanStage.flight = flight;
		flightDuration += duration;
		flightPlanStage.startTime = startTime;
		flightPlanStage.startParams = startParams;
		flightPlanStage.duration = duration;
		flightPlanStage.useUnityPhysics = useUnityPhysics;
		flightPlanStage.hitObjectTag = hitObjectTag;
		return flightPlanStage;
	}

	private void ResetStages()
	{
		activeStageIndex = 0;
		for (int i = 0; i < stageCount; i++)
		{
			stages[i].flight.Reset();
		}
	}

	public HitObjectTag GetHitObjectTag(int stageIndex)
	{
		return stages[Mathf.Clamp(stageIndex, 0, stageCount - 1)].hitObjectTag;
	}

	public override void SetInitialConditions(FlightParams initialConditions, PhysicsBall ball)
	{
		base.initialConditions = initialConditions;
	}

	public override void Reset()
	{
		base.flightTime = 0f;
		ResetStages();
	}

	public override void Update(float deltaTime)
	{
		FlightPlanStage activeStage = GetActiveStage();
		if (activeStage == null || base.flightTime >= flightDuration)
		{
			return;
		}
		activeStage.flight.Update(deltaTime);
		base.flightTime += deltaTime;
		if (base.flightTime >= activeStage.startTime + activeStage.duration)
		{
			Vector3 hitPoint = activeStage.flight.Position();
			Vector3 hitVel = activeStage.flight.Velocity();
			HitObjectTag hitObjectTag = activeStage.hitObjectTag;
			if (activeStageIndex < stageCount - 1)
			{
				activeStageIndex++;
				activeStage = GetActiveStage();
				hitPoint = activeStage.flight.Position();
				hitVel = activeStage.flight.Velocity();
				activeStage.flight.Update(base.flightTime - activeStage.startTime);
			}
			if (onCollision != null)
			{
				onCollision(hitPoint, hitVel, hitObjectTag);
			}
		}
	}

	public override Vector3 Position()
	{
		FlightPlanStage activeStage = GetActiveStage();
		return activeStage.flight.Position();
	}

	public override Vector3 Velocity()
	{
		FlightPlanStage activeStage = GetActiveStage();
		return activeStage.flight.Velocity();
	}

	public override Vector3 AngularVelocity()
	{
		FlightPlanStage activeStage = GetActiveStage();
		return activeStage.flight.AngularVelocity();
	}

	public override Vector3 PositionAt(float time)
	{
		int stageIndexForTime = GetStageIndexForTime(time);
		if (stageIndexForTime < 0)
		{
			return Vector3.zero;
		}
		FlightPlanStage flightPlanStage = stages[stageIndexForTime];
		return flightPlanStage.flight.PositionAt(time - flightPlanStage.startTime);
	}

	public override Vector3 VelocityAt(float time)
	{
		int stageIndexForTime = GetStageIndexForTime(time);
		if (stageIndexForTime < 0)
		{
			return Vector3.zero;
		}
		FlightPlanStage flightPlanStage = stages[stageIndexForTime];
		return flightPlanStage.flight.VelocityAt(time - flightPlanStage.startTime);
	}

	public override Vector3 AngularVelocityAt(float time)
	{
		int stageIndexForTime = GetStageIndexForTime(time);
		if (stageIndexForTime < 0)
		{
			return Vector3.zero;
		}
		FlightPlanStage flightPlanStage = stages[stageIndexForTime];
		return flightPlanStage.flight.AngularVelocityAt(time - flightPlanStage.startTime);
	}
}
